#include "pgngame.h"
#include <QDebug>
#include <QStringList>
#include <QRegExp>

PGNGame::PGNGame()
{
    m_eventName.clear();
    m_siteName.clear();
    m_date.clear();
    m_roundNumber.clear();
    m_whitePlayer.clear();
    m_blackPlayer.clear();
    m_result.clear();
    m_moves.clear();
}

void PGNGame::debug() const
{
    qDebug()<<"Event = "<<event();
    qDebug()<<"Site = "<<site();
    qDebug()<<"Round = "<<round();
    qDebug()<<"White = "<<whitePlayer();
    qDebug()<<"Black = "<<blackPlayer();
    qDebug()<<"Result = "<<result();
    qDebug()<<"Moves = "<<moves();
}

void PGNGame::setEvent(QString eventName)
{
    m_eventName = eventName;
}

QString PGNGame::event() const
{
    return m_eventName;
}

void PGNGame::setSite(QString siteName)
{
    m_siteName = siteName;
}

QString PGNGame::site() const
{
    return m_siteName;
}

void PGNGame::setDate(QString date)
{
    m_date = date;
}

QString PGNGame::date() const
{
    return m_date;
}

void PGNGame::setRound(QString roundNumber)
{
    m_roundNumber = roundNumber;
}

QString PGNGame::round() const
{
    return m_roundNumber;
}

void PGNGame::setWhitePlayersName(QString name)
{
    m_whitePlayer = name;
}

QString PGNGame::whitePlayer() const
{
    return m_whitePlayer;
}

void PGNGame::setBlackPlayersName(QString name)
{
    m_blackPlayer = name;
}

QString PGNGame::blackPlayer() const
{
    return m_blackPlayer;
}

void PGNGame::setResult(QString result)
{
    m_result = result;
}

QString PGNGame::result() const
{
    return m_result;
}

void PGNGame::setMoves(QString movesList)
{
    m_moves = movesList;
}

QString PGNGame::moves() const
{
    return m_moves;
}

QStringList PGNGame::splitMoves() const
{
    QStringList movesText = m_moves.split(QRegExp("[0-9]+\\."), QString::SkipEmptyParts);
    qDebug()<<"parse result"<<movesText<<" size:"<<movesText.size();
    return movesText;
}

int PGNGame::parseMoves()
{
    QStringList textMoves = splitMoves();
    for(QStringList::iterator i= textMoves.begin();
        i != textMoves.end();
        i++)
        {
            moves_pair tmp;
            clearPair(tmp);
            compileMove(*i, tmp);
            m_parsedMoves.push_back(tmp);

        }
    return m_parsedMoves.size();
}

void PGNGame::clearPair(moves_pair &pair) const
{
    pair.white.check = false;
    pair.white.destination.letter = -1;
    pair.white.destination.numeric = -1;
    pair.white.figure = -1;
    pair.white.has_source = false;
    pair.white.is_correct = false;
    pair.white.mat = false;
    pair.white.source.letter = -1;
    pair.white.source.numeric = -1;
    pair.white.is_castling = false;
    pair.white.is_long_castling = false;
    pair.white.is_eating = false;
    pair.white.is_white = true;

    pair.black.check = false;
    pair.black.destination.letter = -1;
    pair.black.destination.numeric = -1;
    pair.black.figure = -1;
    pair.black.has_source = false;
    pair.black.is_correct = false;
    pair.black.mat = false;
    pair.black.source.letter = -1;
    pair.black.source.numeric = -1;
    pair.black.is_castling = false;
    pair.black.is_long_castling = false;
    pair.black.is_eating = false;
    pair.black.is_white = false;
}

void PGNGame::compileMove(QString &movesText, moves_pair &pair) const
{
    QStringList mS = movesText.split(" ", QString::SkipEmptyParts);
    if(mS.size() != 2)
    {
        clearPair(pair);
        return;
    }
    pair.white.is_white = true;
    pair.black.is_white = false;
    QString firstM = mS.first();
    QString secongM = mS.last();
    if(firstM.compare("Qa3")==0)
    {
        qDebug()<<"Here!";
    }
    qDebug()<<firstM<<" and "<<secongM;

    if(firstM.compare("O-O") == 0)
    {
        pair.white.is_castling = true;
        pair.white.is_long_castling = false;
    }
    else if(firstM.compare("O-O-O") == 0)
    {
        pair.white.is_castling = true;
        pair.white.is_long_castling = true;
    }
    else
    {
        pair.white.figure = findFigure(firstM.at(0));
    }

    if(secongM.compare("O-O") == 0)
    {
        pair.black.is_castling = true;
        pair.black.is_long_castling = false;
    }
    else if(secongM.compare("O-O-O") == 0)
    {
        pair.black.is_castling = true;
        pair.black.is_long_castling = true;
    }
    else
    {
       pair.black.figure = findFigure(secongM.at(0));
    }

    if(firstM.at(0).isUpper())
        firstM.remove(0,1);

    if(secongM.at(0).isUpper())
        secongM.remove(0,1);


    if(firstM.contains("#"))
        pair.white.mat = true;
    if(secongM.contains("#"))
        pair.black.mat = true;

    if(firstM.contains("x"))
        pair.white.is_eating = true;
    if(secongM.contains("x"))
        pair.black.is_eating = true;

    if(firstM.contains("+"))
        pair.white.check = true;
    if(secongM.contains("+"))
        pair.black.check = true;

    firstM.remove("x");
    firstM.remove("+");
    firstM.remove("#");

    secongM.remove("x");
    secongM.remove("+");
    secongM.remove("#");

    if(firstM.size()>2)
    {
        qDebug()<<"Source aviable for: "<<firstM;
        if(firstM.at(0).isNumber())
        {
            pair.white.has_source = true;
            pair.white.is_source_number = true;
            pair.white.source.numeric = firstM.at(0).toAscii()-'1';
        }
        else if(firstM.at(0).isLetter() && firstM.at(0).isLower())
        {
            pair.white.has_source = true;
            pair.white.is_source_number = false;
            pair.white.source.numeric = firstM.at(0).toAscii()-'a';
        }
        firstM.remove(0,1);
    }

    if(secongM.size()>2)
    {
        if(secongM.at(0).isNumber())
        {
            pair.black.has_source = true;
            pair.black.is_source_number = true;
            pair.black.source.numeric = secongM.at(0).toAscii()-'1';
        }
        else if(secongM.at(0).isLetter() && secongM.at(0).isLower())
        {
            pair.black.has_source = true;
            pair.black.is_source_number = false;
            pair.black.source.numeric = secongM.at(0).toAscii()-'a';
        }
        secongM.remove(0,1);
    }
    if(!pair.white.is_castling)
        pair.white.destination = findPosition(firstM);
    if(!pair.black.is_castling)
        pair.black.destination = findPosition(secongM);

    if(pair.white.is_castling
       || pair.white.mat
       || (
               pair.white.figure != -1
               && (pair.white.destination.letter >= 0)
               && (pair.white.destination.numeric <8)))
       pair.white.is_correct = true;
    if(pair.black.is_castling
           || pair.black.mat
           || (
                   pair.black.figure != -1
                   && (pair.black.destination.letter >= 0)
                   && (pair.black.destination.numeric <8)));
           pair.black.is_correct = true;
}

short PGNGame::findFigure(const QChar &letter) const
{
    if(!letter.isUpper() && (letter >= 'a') && (letter <= 'h'))
    {
        return pawn;
    }
    if(letter == 'P')
        return pawn;
    if(letter == 'N')
        return knight;
    if(letter == 'R')
        return rook;
    if(letter == 'B')
        return bishop;
    if(letter == 'Q')
        return queen;
    if(letter == 'K')
        return king;
    return -pawn;
}

position PGNGame::findPosition(QString moveText) const
{
    position res;
    if(moveText.at(0).isUpper())
        moveText.remove(0, 1);
    bool isParsedCorrect = true;
    if(moveText.at(0).isLetter())
        res.letter  = moveText.at(0).toAscii() - 'a';
    else
        isParsedCorrect = false;

    if(moveText.at(1).isNumber())
        res.numeric = moveText.at(1).toAscii() - '1';
    else
        isParsedCorrect = false;

    if(!isParsedCorrect)
        qDebug()<<"Error whie parsing: "<<moveText;
    return res;
}

QVector<moves_pair> PGNGame::compiledMoves() const
{
    return m_parsedMoves;
}
